#ifndef ARCH_X86_ASM_H
#define ARCH_X86_ASM_H

# ifdef LANG_X86

extern "C"  Address readInstructionPointer();
extern "C"  void    writeStackPointer(Address a);
extern "C"  Address readStackPointer();
extern "C"  void    writeBasePointer(Address a);
extern "C"  Address readBasePointer();
extern "C"  void    writeBRegister(Address a); // Writes EBX/RBX
extern "C"  Address readBRegister(); // Reads EBX/RBX
extern "C"  void    writePageDirectory(Address a);
extern "C"  Address readPageDirectory();
extern "C"  void    writeMsr(u32int reg, u32int hiWord, u32int loWord);
extern "C"  void    enablePaging();
extern "C"  void    startInterrupts();
extern "C"  void    stopInterrupts();
extern "C"  Address getPageFaultAddress();
extern "C"  void    copyPagePhysical(Address src, Address dest);
extern "C"  void    switchToUserMode();
extern "C"  void    fastSyscall();
extern "C"  void    fastSysexit(Address esp0, Address ret);
extern "C"  void    fastSysexitExecve(Address a, Address b, Address sp, Address ip);
extern "C"  Address atomicExchange(Address *lock, Address newVal);
extern "C"  void    setStackPointerAndJumpTo(Address sp, Address addr);
extern "C"  void    flushPageDirectory();

inline void outb(u16int port, u8int value)
{
  asm volatile ("outb %1, %0" : : "dN" (port), "a" (value));
}

inline u8int inb(u16int port)
{
  u8int ret;
  asm volatile ("inb %1, %0" : "=a" (ret) : "dN" (port));
  return ret;
}

inline u16int inw(u16int port)
{
  u16int ret;
  asm volatile ("inw %1, %0" : "=a" (ret) : "dN" (port));
  return ret;
}

#define START_KERNEL 
/*
  u32int __start_kernel_ring3 = 0; \
  asm volatile("mov %%ss, %0" : "=r"(__start_kernel_ring3)); \
  if(__start_kernel_ring3==0x23) \
  { \
    fastSyscall(); \
  }
*/
#ifdef KERNEL

# define END_KERNEL(ret)
//   if(__start_kernel_ring3==0x23)
//   { \
//     fastSysexit(currentKernelStack, (Address)ret); \
//   } \
//   else \
//   { \
//      return ret;\
//   }
  
# define END_KERNEL_VOID
//   if(__start_kernel_ring3==0x23) \
//   { \
//     fastSysexit(currentKernelStack, (Address)0); \
//   } \

#else // #ifdef KERNEL

# define END_KERNEL(ret) \
  if(__start_kernel_ring3==0x23) \
  { \
    fastSysexit(_currentKernelStack, (Address)ret); \
  } \
  else \
  { \
     return ret;\
  }
  
# define END_KERNEL_VOID \
  if(__start_kernel_ring3==0x23) \
  { \
    fastSysexit(_currentKernelStack, (Address)0); \
  } \

#endif // #ifdef KERNEL
//define END_KERNEL \
//  if(__start_kernel_ring3==0x23) \
//  { \
//    fastSysexit(currentKernelStack, 0); \
//  } \

#define END_KERNEL_EXECVE(a, b, sp, ip) \
  fastSysexitExecve(a,b,sp,ip);

# endif // LANG_X86
#endif  // ARCH_X86_ASM_H
